import { _decorator, Component, EventTouch, Input, instantiate, math, Node, Prefab, random, Sprite, SpriteFrame, UITransform, Vec2, Vec3 } from 'cc';
import { Block } from './Block';
import { GameState } from './GameState';
import { LayerRoot } from './LayerRoot';
import { EventDispatcher } from './EventDispatcher';
const { ccclass, property } = _decorator;

@ccclass('Layer1')
export class Layer1 extends Component {
    @property(Prefab)
    block:Prefab = null;
    @property([SpriteFrame])
    blockSprites:SpriteFrame[] = [];

    curBlock:Block = null;
    start() {
        if(GameState.gameMode === 1){
            return;
        }
        this.node.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(Input.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
    }

    getBlockByPosition(worldPosition: Vec3):Block {
        const position = this.node.getComponent(UITransform).convertToNodeSpaceAR(worldPosition);
        let curBlock;
        for(let i = this.node.children.length - 1; i >= 0; i--){
            const block = this.node.children[i];
            if(!block.active) continue;
            const blockScript = block.getComponent(Block);
            if(!blockScript.canTouch()) continue;
            if(block.getComponent(UITransform).getBoundingBox().contains(new Vec2(position.x, position.y))){
                curBlock = blockScript;
                break;
            }
        }
        return curBlock;
    }

    onTouchStart(e: EventTouch) {
        const position = e.getUILocation();
        const block = this.getBlockByPosition(new Vec3(position.x, position.y));
        this.curBlock = block;
        if(this.curBlock){
            if(!this.curBlock.node.active) return;
            block.playStartTouch();
        }
    }

    onTouchEnd(e: EventTouch) {
        if(this.curBlock){
            if(!this.curBlock.node.active) return;
            this.curBlock.payEndTouch();
            this.node.parent.getComponent(LayerRoot).moveBlock(this.curBlock, this.block);
            this.node.parent.getComponent(LayerRoot).playAudio(0);
        }
    }

    onTouchCancel(e: EventTouch) {
        if(this.curBlock){
            if(!this.curBlock.node.active) return;
            this.curBlock.payEndTouch();
            this.node.parent.getComponent(LayerRoot).moveBlock(this.curBlock, this.block);
        }
    }

    protected onDestroy(): void {
        this.node.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.off(Input.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
    }

    addBlock(worldPosition: Vec3):Block {
        const position = this.node.getComponent(UITransform).convertToNodeSpaceAR(worldPosition);
        return this.addBlockByLocalPosition(position);
    }

    startGame(lv:number){
        const lvData = GameState.getLvData(lv);
        let curIndex = 0;
        if(lvData){
            const sprites = this.getRandomSpriteFrames(lvData.types);
            for(let i = 0; i< lvData.list.length; i++){
                const position = new Vec3(lvData.list[i].x, lvData.list[i].y);
                if(i > 0 && i % 3 === 0){
                    curIndex++;
                    if(curIndex >= lvData.types){
                        curIndex = 0
                    }
                }
                const block = this.addBlockByLocalPosition(position);
                block.setSprite(sprites[curIndex]);
                block.refreshSprite();
            }
            
            this.refreshShadow();
        }
    }

    getRandomSpriteFrames(types:number): SpriteFrame[] {
        const randomSprites = this.blockSprites.sort(() => Math.random() - 0.5);
        return randomSprites.slice(0, types);
    }

    addBlockByLocalPosition(localPosition: Vec3):Block {
        const block = instantiate(this.block);
        block.setPosition(localPosition);
        block.setParent(this.node);
        return block.getComponent(Block);
    }

    removeBlock(worldPosition: Vec3) {
        const position = this.node.getComponent(UITransform).convertToNodeSpaceAR(worldPosition)
        for(let i = this.node.children.length - 1; i >= 0; i--){
            const block = this.node.children[i];
            if(block.getComponent(UITransform).getBoundingBox().contains(new Vec2(position.x, position.y))){
                block.removeFromParent();
                break;
            }
        }
    }

    getChildrenLength() {
        return this.node.children.length;
    }

    clearAll() {
        this.node.removeAllChildren();
    }

    refreshShadow() {
        for(let i = 0; i < this.node.children.length; i++){
            const block1 = this.node.children[i].getComponent(Block);
            if(!block1.node.active) continue;
            const block1Box = block1.getBoundingBox();
            block1.show();
            for(let j = i+1; j < this.node.children.length; j++){
                const block2Box = this.node.children[j].getComponent(Block).getBoundingBox();
                if(!this.node.children[j].active) continue;
                if(block1Box.intersects(block2Box)){
                    block1.hide();
                }
            }
        }
    }

    randomBlocks() {
        if(GameState.randomTimes <= 0){
            EventDispatcher.getInstTarget().emit(EventDispatcher.SHOW_TIPS, '没次数了')
            return;
        }
        GameState.randomTimes -= 1;
        if(GameState.randomTimes <= 0){
            this.node.parent.getComponent(LayerRoot).btnRandom.getComponent(Sprite).grayscale = true;
        }
        const temp = [];
        for(let i = 0; i < this.node.children.length; i++){
            const block = this.node.children[i].getComponent(Block);
            if(!block.node.active) continue;
            temp.push(block)
        }
        for(let i = 0; i < temp.length; i++){
            const block = temp[i];
            const other = temp[math.randomRangeInt(0, temp.length)];
            const blockSprite = block.getSpriteFrame();
            const otherSprite = other.getSpriteFrame();
            other.setSprite(blockSprite);
            block.setSprite(otherSprite);
        }
        for(let block of temp){
            block.refreshSprite();
        }
    }

    getBlockSize() {
        return this.node.children.length;
    }
}


